#include "chartviewex.h"
#include <QPainter>
#include <QPointF>
#include <QtCharts/QLegendMarker>
#include <QMessageBox>
#include <QIcon>
#include <QGraphicsLayout>
#include <QFileDialog>
#include <QMouseEvent>
#include <QDebug>

ChartViewEx::ChartViewEx(QWidget *parent)
	:QChartView(parent)
{
	mZoomFactor = 1.8;
	isPress = false;
	isHoverd = false;
	isHoveredEnable = false;

	currentSeries = hoveredSeries = NULL;

	mChart = new QChart();
	mChart->legend()->setAlignment(Qt::AlignRight);
	mChart->layout()->setContentsMargins(0, 0, 0, 0);

	QPen pen;
	pen.setWidth(1);
	pen.setStyle(Qt::DashLine);
	pen.setColor(QColor(96, 96, 96));

	xAxis = new QValueAxis;
	xAxis->setRange(0, 1);
	xAxis->setGridLinePen(pen);
	xAxis->setTickCount(11);

	yAxis = new QValueAxis;
	yAxis->setRange(0, 1);
	yAxis->setGridLinePen(pen);
	yAxis->setTickCount(6);
	yAxis->setReverse(true);

	mChart->setAxisX(xAxis);
	mChart->setAxisY(yAxis);

	setChart(mChart);
	createActions();
	createDialog();

	setRenderHint(QPainter::Antialiasing);
}

void ChartViewEx::createActions()
{
	popMenu = new QMenu();
	setCurvePropertyAction = new QAction("Chart Property", this);
	popMenu->addAction(setCurvePropertyAction);

	popMenu->addSeparator();

	isHoveredEnable = false;
	hoveredEnableAction = new QAction("Hovered Enable", this);
	hoveredEnableAction->setCheckable(true);
	hoveredEnableAction->setChecked(isHoveredEnable);
	popMenu->addAction(hoveredEnableAction);

	isMarkerVisible = false;
	markerAction = new QAction("Marker Visible", this);
	markerAction->setCheckable(true);
	markerAction->setChecked(isMarkerVisible);
	popMenu->addAction(markerAction);

	isLegendVisible = true;
	legendVisibleAction = new QAction("Legend Visible", this);
	legendVisibleAction->setCheckable(true);
	legendVisibleAction->setChecked(isLegendVisible);
	popMenu->addAction(legendVisibleAction);

	popMenu->addSeparator();

	selectAllCurve = new QAction("Display All", this);
	popMenu->addAction(selectAllCurve);

	hideAllCurve = new QAction("Hide All", this);
	popMenu->addAction(hideAllCurve);

	popMenu->addSeparator();

	saveImgAction = new QAction("Save Image", this);
	popMenu->addAction(saveImgAction);

	connect(setCurvePropertyAction, &QAction::triggered, this, &ChartViewEx::showSetPropertyDialog);
	connect(saveImgAction, &QAction::triggered, this, &ChartViewEx::saveImage);
	connect(legendVisibleAction, &QAction::triggered, this, &ChartViewEx::legendVisible);
	connect(selectAllCurve, &QAction::triggered, this, &ChartViewEx::SelectAllNorNot);
	connect(hideAllCurve, &QAction::triggered, this, &ChartViewEx::SelectAllNorNot);
	connect(markerAction, &QAction::triggered, this, &ChartViewEx::markerVisible);
	connect(hoveredEnableAction, &QAction::triggered, this, &ChartViewEx::hoveredEnable);
}

void ChartViewEx::createDialog()
{
	curveDialog = new QDialog();
	curveDialog->setWindowTitle("Curve Property");

	lbLineName = new QLabel("Name:");
	lbLineType = new QLabel("Type:");
	lbLineWidth = new QLabel("Width:");
	lbColor = new QLabel("Color:");

	spinBoxLineWidth = new QSpinBox;
	spinBoxLineWidth->setRange(1, 10);

	lELineName = new QLineEdit;

	cbBoxLineType = new QComboBox;
	cbBoxLineType->addItem("Solid");
	cbBoxLineType->addItem("Dash");
	cbBoxLineType->addItem("Dot");
	cbBoxLineType->addItem("DashDot");
	cbBoxLineType->addItem("DashDotDot");

	cbBoxLineColor = new QComboBox;
	fillColorList(cbBoxLineColor);

	QGridLayout *layout1 = new QGridLayout;
	layout1->addWidget(lbLineName, 0, 0);
	layout1->addWidget(lELineName, 0, 1);
	layout1->addWidget(lbLineWidth, 1, 0);
	layout1->addWidget(spinBoxLineWidth, 1, 1);
	layout1->addWidget(lbLineType, 2, 0);
	layout1->addWidget(cbBoxLineType, 2, 1);
	layout1->addWidget(lbColor, 3, 0);
	layout1->addWidget(cbBoxLineColor);

	layout1->setSizeConstraint(QLayout::SetFixedSize);
	curveDialog->setLayout(layout1);

	chartDialog = new QDialog();
	chartDialog->setWindowTitle("Chart Property");

	lbChartTitle = new QLabel("Title:");
	lbChartBackground = new QLabel("Background:");
	lbChartForeground = new QLabel("Foreground:");
	lbPlotAreaColor = new QLabel("PlotArea Color:");

	lEChartTitle = new QLineEdit;
	cbBoxBkColor = new QComboBox;
	fillColorList(cbBoxBkColor);
	cbBoxFrColor = new QComboBox;
	fillColorList(cbBoxFrColor);
	cbBoxPlotAreaColor = new QComboBox;
	fillColorList(cbBoxPlotAreaColor);

	lbLegendAlign = new QLabel("Legend Align:");
	cbBoxLegendAlign = new QComboBox;
	cbBoxLegendAlign->addItem("Top");
	cbBoxLegendAlign->addItem("Left");
	cbBoxLegendAlign->addItem("Right");
	cbBoxLegendAlign->addItem("Bottom");
	cbBoxLegendAlign->addItem("None");

	lbZoomFactor = new QLabel("Zoom Factor:");
	spinBoxZoomFactor = new QDoubleSpinBox;
	spinBoxZoomFactor->setRange(1.0, 2.0);
	spinBoxZoomFactor->setSingleStep(0.1);

	QGroupBox *groupBoxBasic = new QGroupBox("Basic Setting:");
	QGridLayout *layoutBasic = new QGridLayout;
	layoutBasic->addWidget(lbChartTitle, 0, 0);
	layoutBasic->addWidget(lEChartTitle, 0, 1);
	layoutBasic->addWidget(lbChartBackground, 1, 0);
	layoutBasic->addWidget(cbBoxBkColor, 1, 1);
	layoutBasic->addWidget(lbChartForeground, 2, 0);
	layoutBasic->addWidget(cbBoxFrColor, 2, 1);
	layoutBasic->addWidget(lbPlotAreaColor, 3, 0);
	layoutBasic->addWidget(cbBoxPlotAreaColor, 3, 1);
	layoutBasic->addWidget(lbLegendAlign, 4, 0);
	layoutBasic->addWidget(cbBoxLegendAlign, 4, 1);
	layoutBasic->addWidget(lbZoomFactor, 5, 0);
	layoutBasic->addWidget(spinBoxZoomFactor, 5, 1);
	groupBoxBasic->setLayout(layoutBasic);



	QGroupBox *groupBoxAxisX = new QGroupBox("X Axis Setting:");
	lbXAixsName = new QLabel("Name:");
	lEXAxisName = new QLineEdit;

	lbXAxisDecimal = new QLabel("Decimal:");
	spinBoxXDecimal = new QSpinBox;
	spinBoxXDecimal->setValue(2);
	spinBoxXDecimal->setRange(0, 5);

	lbXAxisMin = new QLabel("Min Value:");
	spinBoxXMin = new QDoubleSpinBox;
	spinBoxXMin->setRange(-10000000, 100000000);

	lbXAxisMax = new QLabel("Max Value:");
	spinBoxXMax = new QDoubleSpinBox;
	spinBoxXMax->setRange(-10000000, 100000000);

	ckBoxXReverse = new QCheckBox;
	ckBoxXReverse->setText("Reverse");

	QGridLayout *layoutX = new QGridLayout;
	layoutX->addWidget(lbXAixsName, 0, 0);
	layoutX->addWidget(lEXAxisName, 0, 1);
	layoutX->addWidget(lbXAxisDecimal, 1, 0);
	layoutX->addWidget(spinBoxXDecimal, 1, 1);
	layoutX->addWidget(lbXAxisMin, 2, 0);
	layoutX->addWidget(spinBoxXMin, 2, 1);
	layoutX->addWidget(lbXAxisMax, 3, 0);
	layoutX->addWidget(spinBoxXMax, 3, 1);
	layoutX->addWidget(ckBoxXReverse, 4, 0);
	groupBoxAxisX->setLayout(layoutX);


	QGroupBox *groupBoxAxisY = new QGroupBox("Y Axis Setting:");
	lbYAxisName = new QLabel("Name:");
	lEYAxisName = new QLineEdit;

	lbYAxisDecimal = new QLabel("Decimal:");
	spinBoxYDecimal = new QSpinBox;
	spinBoxYDecimal->setValue(2);
	spinBoxYDecimal->setRange(0, 5);

	lbYAxisMin = new QLabel("Min Value:");
	spinBoxYMin = new QDoubleSpinBox;
	spinBoxYMin->setRange(-10000000, 100000000);
	lbYAxisMax = new QLabel("Max Value:");
	spinBoxYMax = new QDoubleSpinBox;
	spinBoxYMax->setRange(-10000000, 100000000);
	ckBoxYReverse = new QCheckBox;
	ckBoxYReverse->setText("Reverse");

	QGridLayout *layoutY = new QGridLayout;
	layoutY->addWidget(lbYAxisName, 0, 0);
	layoutY->addWidget(lEYAxisName, 0, 1);
	layoutY->addWidget(lbYAxisDecimal, 1, 0);
	layoutY->addWidget(spinBoxYDecimal, 1, 1);
	layoutY->addWidget(lbYAxisMin, 2, 0);
	layoutY->addWidget(spinBoxYMin, 2, 1);
	layoutY->addWidget(lbYAxisMax, 3, 0);
	layoutY->addWidget(spinBoxYMax, 3, 1);
	layoutY->addWidget(ckBoxYReverse, 4, 0);
	groupBoxAxisY->setLayout(layoutY);

	QGroupBox *groupBoxGrid = new QGroupBox("Grid Setting:");
	lbXGridCount = new QLabel("Row :");
	spinBoxXGridCount = new QSpinBox;
	spinBoxXGridCount->setValue(5);

	lbYGridCount = new QLabel("Column:");
	spinBoxYGridCount = new QSpinBox;
	spinBoxYGridCount->setValue(10);

	lbGridColor = new QLabel("Color");
	cbBoxGridColor = new QComboBox;
	fillColorList(cbBoxGridColor);

	QGridLayout *layoutGrid = new QGridLayout;
	layoutGrid->addWidget(lbXGridCount, 0, 0);
	layoutGrid->addWidget(spinBoxXGridCount, 0, 1);
	layoutGrid->addWidget(lbYGridCount, 1, 0);
	layoutGrid->addWidget(spinBoxYGridCount, 1, 1);
	layoutGrid->addWidget(lbGridColor, 2, 0);
	layoutGrid->addWidget(cbBoxGridColor, 2, 1);
	groupBoxGrid->setLayout(layoutGrid);

	QGridLayout *layout2 = new QGridLayout;
	layout2->addWidget(groupBoxBasic);
	layout2->addWidget(groupBoxAxisX);
	layout2->addWidget(groupBoxAxisY);
	layout2->addWidget(groupBoxGrid);
	layout2->setSizeConstraint(QLayout::SetFixedSize);
	chartDialog->setLayout(layout2);

	connect(lEChartTitle, &QLineEdit::textChanged, this, &ChartViewEx::setChartName);
	connect(lEXAxisName, &QLineEdit::textChanged, this, &ChartViewEx::setXAxisName);
	connect(lEYAxisName, &QLineEdit::textChanged, this, &ChartViewEx::setYAxisName);
	
	connect(cbBoxLegendAlign, SIGNAL(currentIndexChanged(int)), this, SLOT(getLegendAlign(int)));
	connect(lELineName, SIGNAL(textChanged(QString)), this, SLOT(getLineName(QString)));
	connect(cbBoxLineType, SIGNAL(currentIndexChanged(int)), this, SLOT(getLineType(int)));
	
	connect(spinBoxLineWidth, SIGNAL(valueChanged(int)), this, SLOT(getSpinBoxValue(int)));
	connect(spinBoxXDecimal, SIGNAL(valueChanged(int)), this, SLOT(getSpinBoxValue(int)));
	connect(spinBoxXGridCount, SIGNAL(valueChanged(int)), this, SLOT(getSpinBoxValue(int)));
	connect(spinBoxYDecimal, SIGNAL(valueChanged(int)), this, SLOT(getSpinBoxValue(int)));
	connect(spinBoxYGridCount, SIGNAL(valueChanged(int)), this, SLOT(getSpinBoxValue(int)));
	
	connect(cbBoxBkColor, SIGNAL(currentIndexChanged(int)), this, SLOT(getColor(int)));
	connect(cbBoxLineColor, SIGNAL(currentIndexChanged(int)), this, SLOT(getColor(int)));
	connect(cbBoxFrColor, SIGNAL(currentIndexChanged(int)), this, SLOT(getColor(int)));
	connect(cbBoxGridColor, SIGNAL(currentIndexChanged(int)), this, SLOT(getColor(int)));
	connect(cbBoxPlotAreaColor, SIGNAL(currentIndexChanged(int)), this, SLOT(getColor(int)));

	connect(spinBoxZoomFactor, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this, &ChartViewEx::getDoubleSpinBoxValue);
	connect(spinBoxXMin, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this, &ChartViewEx::getDoubleSpinBoxValue);
	connect(spinBoxXMax, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this, &ChartViewEx::getDoubleSpinBoxValue);
	connect(spinBoxYMin, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this, &ChartViewEx::getDoubleSpinBoxValue);
	connect(spinBoxYMax, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this, &ChartViewEx::getDoubleSpinBoxValue);
	connect(ckBoxXReverse, &QCheckBox::clicked, this, &ChartViewEx::setOptionEnable);
	connect(ckBoxXReverse, &QCheckBox::clicked, this, &ChartViewEx::setOptionEnable);
}

void ChartViewEx::fillColorList(QComboBox *cbBox)
{
	QStringList colorList = QColor::colorNames();
	foreach(QString color, colorList) {
		QPixmap pix(QSize(100, 20));
		pix.fill(QColor(color));
		cbBox->addItem(QIcon(pix), NULL);
		cbBox->setIconSize(QSize(100, 20));
		cbBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
	}
}

void ChartViewEx::contextMenuEvent(QContextMenuEvent *event)
{
	int displayCount = 0;
	int hideCount = 0;

	QList<QLegendMarker*> lstMarker = mChart->legend()->markers();
	for (int i = 0; i < lstMarker.count(); i++)
	{
		QLegendMarker* marker = lstMarker.at(i);
		switch (marker->type()) {
		case QLegendMarker::LegendMarkerTypeXY:
		{
			if (isLegendVisible)
			{
				if (marker->pen().color().alphaF() == 1.0f)
				{
					displayCount++;
				}
				else
				{
					hideCount++;
				}
			}
			else
			{
				if (marker->series()->isVisible())
				{
					displayCount++;
				}
				else
				{
					hideCount++;
				}
			}

			break;
		}
		case QLegendMarker::LegendMarkerTypeArea:
		case QLegendMarker::LegendMarkerTypeBar:
		case QLegendMarker::LegendMarkerTypePie:
		case QLegendMarker::LegendMarkerTypeBoxPlot:
		case QLegendMarker::LegendMarkerTypeCandlestick:
		default:
		{
			break;
		}
		}
	}

	if (displayCount == mChart->series().count())
	{
		selectAllCurve->setEnabled(false);
	}
	else
	{
		selectAllCurve->setEnabled(true);
	}

	if (hideCount == mChart->series().count())
	{
		hideAllCurve->setEnabled(false);
	}
	else
	{
		hideAllCurve->setEnabled(true);
	}

	popMenu->exec(QCursor::pos());
	event->accept();
}

void ChartViewEx::mouseMoveEvent(QMouseEvent *event)
{
	if (isPress)
	{
		posEnd = event->pos();
		checkPointValid(posEnd);

		this->viewport()->update();
	}
	else
	{
		QChartView::mouseMoveEvent(event);
	}
}

void ChartViewEx::mousePressEvent(QMouseEvent *event)
{
	if (event->buttons() & Qt::LeftButton)
	{
		if (mChart->plotArea().contains(event->pos()))
		{
			setHoveredSigal(posCur, false);

			setCursor(Qt::CrossCursor);
			isPress = true;
			posStart = posEnd = event->pos();
		}
	}

	QChartView::mousePressEvent(event);
}

void ChartViewEx::mouseReleaseEvent(QMouseEvent *event)
{
	if ((event->button() == Qt::LeftButton))
	{
		if (isPress)
		{
			QRectF rect1(posStart, posEnd);
			QRectF rect2 = rect1.normalized();
			if (rect1 == rect2)
			{
				QPointF pos = event->pos();
				checkPointValid(pos);

				QRectF rect;
				rect.setTopLeft(posStart);
				rect.setBottomRight(pos);
				mChart->zoomIn(rect);
			}
			else
			{
				mChart->zoomReset();
			}
		}

		setCursor(Qt::ArrowCursor);
		isPress = false;
		this->viewport()->update();
	}


	QChartView::mouseReleaseEvent(event);
}

void ChartViewEx::wheelEvent(QWheelEvent *e)
{
	if (e->delta() > 0)
	{
		mChart->zoom(1 / mZoomFactor);
		mChart->zoomIn();
	}
	else
	{
		mChart->zoom(mZoomFactor);
		mChart->zoomOut();
	}

	setHoveredSigal(posCur, false);
	this->viewport()->update();
}

void ChartViewEx::addCurveData(CCurveData *data)
{
	QList<float> pX = data->GetData("X");
	QList<float> pY = data->GetData("Y");
	if (pX.count() != pY.count())
	{
		QMessageBox::warning(this, "Warning", "There are some error in the data!");
		return;
	}

	QString name = data->GetCurveName();

	for (int i = 0; i < mChart->series().count(); i++)
	{
		if (name == mChart->series().at(i)->name())
		{
			QMessageBox::warning(this, "Warning", "There is exist the same name series in the chart!");
			return;
		}
	}

	QLineSeries *series = new QLineSeries;
	QList<QPointF> lstP;
	if (mChart->series().count() == 0)
	{
		mXMax = mXMin = pX[0];
		mYMax = mYMin = pY[0];
	}

	for (int i = 0; i < pX.count(); i++)
	{
		lstP.append(QPointF(pX[i], pY[i]));

		mXMax = pX[i] > mXMax ? pX[i] : mXMax;
		mXMin = pX[i] < mXMin ? pX[i] : mXMin;
		mYMax = pY[i] > mYMax ? pY[i] : mYMax;
		mYMin = pY[i] < mYMin ? pY[i] : mYMin;
	}

	series->append(lstP);

	connect(series, &QLineSeries::hovered, this, &ChartViewEx::setHoveredSigal);
	connect(series, &QLineSeries::doubleClicked, this, &ChartViewEx::showSetPropertyDialog);

	mChart->addSeries(series);

	series->setName(data->GetCurveName());
	series->setColor(data->GetLineColor());

	xAxis->setRange(mXMin, mXMax);

	if (mYMax == mYMin)
	{
		mChart->axisY()->setRange(mYMin - 0.05, mYMax + 0.05);
	}
	else
	{
		mChart->axisY()->setRange(mYMin - (mYMax - mYMin) *0.05, mYMax + (mYMax - mYMin) * 0.05);
	}

	series->attachAxis(xAxis);
	series->attachAxis(yAxis);
	//mChart->setAxisX(xAxis, series);
	//mChart->setAxisY(yAxis, series);

	connectMarkers();
}

void ChartViewEx::connectMarkers()
{
	foreach(QLegendMarker* marker, mChart->legend()->markers()) {
		QObject::disconnect(marker, SIGNAL(clicked()), this, SLOT(handleMarkerClicked()));
		QObject::connect(marker, SIGNAL(clicked()), this, SLOT(handleMarkerClicked()));
	}
}

void ChartViewEx::legendVisible()
{
	isLegendVisible = !isLegendVisible;

	QList<QLegendMarker*> lstMarker = mChart->legend()->markers();
	for (int i = 0; i < lstMarker.count(); i++)
	{
		QLegendMarker* marker = lstMarker.at(i);
		switch (marker->type()) {
		case QLegendMarker::LegendMarkerTypeXY:
		{
			if (!marker->series()->isVisible())
			{
				marker->setVisible(isLegendVisible);
			}
			break;
		}
		case QLegendMarker::LegendMarkerTypeArea:
		case QLegendMarker::LegendMarkerTypeBar:
		case QLegendMarker::LegendMarkerTypePie:
		case QLegendMarker::LegendMarkerTypeBoxPlot:
		case QLegendMarker::LegendMarkerTypeCandlestick:
		default:
		{
			break;
		}
		}
	}

	mChart->legend()->hide();
	mChart->legend()->show();
}

void ChartViewEx::handleMarkerClicked()
{
	QLegendMarker* marker = qobject_cast<QLegendMarker*> (sender());
	switch (marker->type()) {
	case QLegendMarker::LegendMarkerTypeXY:
	{
		marker->series()->setVisible(!marker->series()->isVisible());
		marker->setVisible(isLegendVisible);

		qreal aplha = 1.0;
		if (!marker->series()->isVisible())
		{
			aplha = 0.5;
		}

		QBrush brush;
		brush = marker->brush();
		QColor color;
		color = brush.color();
		color.setAlphaF(aplha);
		brush.setColor(color);
		marker->setBrush(brush);

		QPen pen;
		pen = marker->pen();
		color = pen.color();
		color.setAlphaF(aplha);
		pen.setColor(color);
		marker->setPen(pen);
		break;
	}
	case QLegendMarker::LegendMarkerTypeArea:
	case QLegendMarker::LegendMarkerTypeBar:
	case QLegendMarker::LegendMarkerTypePie:
	case QLegendMarker::LegendMarkerTypeBoxPlot:
	case QLegendMarker::LegendMarkerTypeCandlestick:
	default:
	{
		break;
	}
	}
}

void ChartViewEx::hoveredEnable()
{
	isHoveredEnable = !isHoveredEnable;

	//if (isHoveredEnable)
	//{
	//	for (int i = 0; i<mChart->series().count(); i++)
	//	{
	//		connect(qobject_cast<QLineSeries*> (mChart->series().at(i)), &QLineSeries::hovered, this, &ChartViewEx::setHoveredSigal);
	//	}
	//}
	//else
	//{
	//	for (int i = 0; i<mChart->series().count(); i++)
	//	{

	//		disconnect(qobject_cast<QLineSeries*> (mChart->series().at(i)), &QLineSeries::hovered, this, &ChartViewEx::setHoveredSigal);
	//	}
	//}
}

void ChartViewEx::paintEvent(QPaintEvent *event)
{
	QChartView::paintEvent(event);

	QPainter painter(this->viewport());
	QPen pen;
	pen.setWidth(2);
	pen.setColor(QColor(96, 96, 96));

	painter.setPen(pen);

	QRectF rect = mChart->plotArea();
	painter.drawRect(rect);

	if (isPress || isHoverd)
	{
		pen.setWidth(1);
		pen.setStyle(Qt::DashLine);
		if (isPress)
		{
			pen.setColor(QColor(96, 96, 96));
			painter.setPen(pen);
			QBrush brush(QColor(255, 215, 0, 102));
			painter.setBrush(brush);
			painter.drawRect(posStart.x(), posStart.y(), posEnd.x() - posStart.x(), posEnd.y() - posStart.y());
		}

		if (isHoverd)
		{
			QPointF pos = mChart->mapToPosition(posCur);

			if (mChart->plotArea().contains(pos))
			{
				QPointF origin = mChart->plotArea().bottomLeft();
				QPointF rightTopP = mChart->plotArea().topRight();

				QPointF lineP11 = QPointF(pos.x(), origin.y());
				QPointF lineP12 = QPointF(pos.x(), rightTopP.y());
				QPointF lineP21 = QPoint(origin.x(), pos.y());
				QPointF lineP22 = QPointF(rightTopP.x(), pos.y());

				pen.setColor(Qt::red);
				painter.setPen(pen);
				painter.drawLine(lineP11, lineP12);
				painter.drawLine(lineP21, lineP22);
				QBrush brush(QColor(255, 215, 0, 102));
				painter.drawText(pos.x() + 5, pos.y() - 5, tr("(%1,%2)").arg(posCur.x()).arg(posCur.y()));
			}
		}
	}
}

void ChartViewEx::setHoveredSigal(const QPointF &point, bool state)
{
	if (!isHoveredEnable)
		return;

	isHoverd = state;
	QLineSeries* series = qobject_cast<QLineSeries*> (sender());
	if (series != NULL)
	{
		if (state)
		{
			hoveredSeries = series;
			setCursor(Qt::CrossCursor);
			posCur = point;

			QPen pen = hoveredSeries->pen();
			pen.setWidth(2 * pen.width());
			hoveredSeries->setPen(pen);
		}
		else
		{
			if (hoveredSeries != NULL)
			{
				QPen pen = hoveredSeries->pen();
				pen.setWidth(pen.width() / 2);
				hoveredSeries->setPen(pen);

				setCursor(Qt::ArrowCursor);

				hoveredSeries = NULL;
			}
		}
	}
	else
	{
		if (hoveredSeries != NULL)
		{
			QPen pen = hoveredSeries->pen();
			pen.setWidth(pen.width() / 2);
			hoveredSeries->setPen(pen);

			setCursor(Qt::ArrowCursor);

			hoveredSeries = NULL;
		}
	}

	this->viewport()->update();
}

void ChartViewEx::showSetPropertyDialog()
{
	currentSeries = qobject_cast<QLineSeries*> (sender());
	if (currentSeries == NULL)
	{
		lEChartTitle->setText(mChart->title());

		qDebug() << mChart->axisX()->titleText();
		lEXAxisName->setText(mChart->axisX()->titleText());
		lEYAxisName->setText(mChart->axisY()->titleText());

		if (!mChart->legend()->isVisible())
		{
			cbBoxLegendAlign->setCurrentIndex(cbBoxLegendAlign->count() - 1);
		}
		else
		{
			Qt::Alignment align = mChart->legend()->alignment();
			QString strFind;
			switch (align) {
			case Qt::AlignTop:
				strFind = "Top";
				break;
			case Qt::AlignLeft:
				strFind = "Left";
				break;
			case Qt::AlignBottom:
				strFind = "Bottom";
				break;
			case Qt::AlignRight:
				strFind = "Right";
				break;
			default:
				break;
			}
			for (int i = 0; i < cbBoxLegendAlign->count() - 1; i++)
			{
				if (cbBoxLegendAlign->itemText(i).contains(strFind, Qt::CaseInsensitive))
				{
					cbBoxLegendAlign->setCurrentIndex(i);
					break;
				}
			}
		}

		spinBoxZoomFactor->setValue(mZoomFactor);

		chartDialog->setModal(true);
		chartDialog->show();
	}
	else
	{
		lELineName->setText(currentSeries->name());
		QPen pen = currentSeries->pen();
		spinBoxLineWidth->setValue(pen.width());
		Qt::PenStyle style = pen.style();
		cbBoxLineType->setCurrentIndex((int)style - 1);

		QStringList colorList = QColor::colorNames();
		for (int i = 0; i < colorList.count(); i++)
		{
			QColor color(colorList[i]);
			if (color.name() == currentSeries->color().name())
			{
				cbBoxLineColor->setCurrentIndex(i);
				break;
			}
		}

		curveDialog->setWindowFlags(Qt::WindowStaysOnTopHint | Qt::Dialog);
		curveDialog->setModal(false);
		curveDialog->show();
	}
}

void ChartViewEx::getLegendAlign(int index)
{
	Qt::Alignment align;
	switch (index) {
	case 0:
		align = Qt::AlignTop;
		break;
	case 1:
		align = Qt::AlignLeft;
		break;
	case 2:
		align = Qt::AlignRight;
		break;
	case 3:
		align = Qt::AlignBottom;
		break;
	case 4:
		mChart->legend()->hide();
	default:
		break;
	}

	if (index != cbBoxLegendAlign->count() - 1)
	{
		mChart->legend()->setVisible(true);
		mChart->legend()->setAlignment(align);
	}
}

void ChartViewEx::getLineType(int index)
{
	index = index + 1;
	QPen pen = currentSeries->pen();
	pen.setStyle((Qt::PenStyle)index);
	currentSeries->setPen(pen);
}

void ChartViewEx::getLineName(const QString &name)
{
	currentSeries->setName(name);
}

void ChartViewEx::getSpinBoxValue(int index)
{
	QSpinBox* spinBox = qobject_cast<QSpinBox*> (sender());

	if(spinBox == spinBoxLineWidth)
	{
		QPen pen = currentSeries->pen();
		pen.setWidth(index);
		currentSeries->setPen(pen);
	}
	else if (spinBox == spinBoxXDecimal)
	{
		spinBoxXMax->setDecimals(index);
		spinBoxXMin->setDecimals(index);

		QString str = QString("%.%1f").arg(index);
		setAxisXDecimalNumber(str);
	}
	else if (spinBox == spinBoxYDecimal)
	{
		spinBoxYMax->setDecimals(index);
		spinBoxYMin->setDecimals(index);

		QString str = QString("%.%1f").arg(index);
		setAxisYDecimalNumber(str);
	}
	else if (spinBox == spinBoxXGridCount)
	{
		setGridNumber(xAxis->tickCount(), index);
	}
	else if (spinBox == spinBoxYGridCount)
	{
		setGridNumber(index, yAxis->tickCount());
	}
}

void ChartViewEx::getColor(int index)
{
	QComboBox* cbBox = qobject_cast<QComboBox*> (sender());
	QStringList colorList = QColor::colorNames();

	QColor color = QColor(colorList[index]);
	if (cbBox == cbBoxBkColor)
	{
		setChartBackgroundColor(color);
	}
	else if (cbBox == cbBoxFrColor)
	{
		setChartForegroundColor(color);
	}
	else if (cbBox == cbBoxGridColor)
	{
		setGridColor(color);
	}
	else if (cbBox == cbBoxPlotAreaColor)
	{
		setChartPlotAreaColor(color);
	}	 
	else if (cbBox == cbBoxLineColor)
	{
		currentSeries->setColor(color);
		QList<QLegendMarker*> lstMarker = mChart->legend()->markers(currentSeries);

		for (int i = 0; i < lstMarker.count(); i++)
		{
			QLegendMarker* marker = lstMarker.at(i);
			switch (marker->type()) {
			case QLegendMarker::LegendMarkerTypeXY:
			{
				QBrush brush;
				brush = marker->brush();
				color.setAlphaF(brush.color().alphaF());
				brush.setColor(color);
				marker->setBrush(brush);

				QPen pen;
				pen = marker->pen();
				color.setAlphaF(pen.color().alphaF());
				pen.setColor(color);
				marker->setPen(pen);
				break;
			}
			case QLegendMarker::LegendMarkerTypeArea:
			case QLegendMarker::LegendMarkerTypeBar:
			case QLegendMarker::LegendMarkerTypePie:
			case QLegendMarker::LegendMarkerTypeBoxPlot:
			case QLegendMarker::LegendMarkerTypeCandlestick:
			default:
			{
				break;
			}
			}
		}
	}
}

void ChartViewEx::setOptionEnable(bool enable)
{
	QCheckBox* ckBox = qobject_cast<QCheckBox*> (sender());
	if (ckBox == ckBoxXReverse)
	{
		if(xAxis->isReverse() != enable)
		{
			xAxis->setReverse(enable);
		}	
	}
	else if(ckBox == ckBoxYReverse)
	{
		if (yAxis->isReverse() != enable)
		{
			yAxis->setReverse(enable);
		}
	}
}

void ChartViewEx::setXAxisName(const QString &name)
{
	mChart->axisX()->setTitleVisible(true);

	QFont font = mChart->axisX()->titleFont();
	font.setWeight(QFont::DemiBold);
	font.setPointSize(10);

	mChart->axisX()->setTitleFont(font);
	mChart->axisX()->setTitleText(name);
}

void ChartViewEx::setYAxisName(const QString &name)
{
	mChart->axisY()->setTitleVisible(true);

	QFont font = mChart->axisY()->titleFont();
	font.setWeight(QFont::DemiBold);
	font.setPointSize(10);
	mChart->axisY()->setTitleFont(font);
	mChart->axisY()->setTitleText(name);
}

void ChartViewEx::setChartName(const QString &name)
{
	QFont font = mChart->titleFont();
	font.setWeight(QFont::ExtraBold);
	font.setPointSize(16);
	mChart->setTitleFont(font);

	mChart->setTitle(name);
}

void ChartViewEx::getDoubleSpinBoxValue(double value)
{
	QDoubleSpinBox* spinBox = qobject_cast<QDoubleSpinBox*> (sender());
	if (spinBox == spinBoxXMax)
	{
		xAxis->setMax(value);
	}
	else if (spinBox == spinBoxXMin)
	{
		xAxis->setMin(value);
	}
	else if (spinBox == spinBoxYMax)
	{
		yAxis->setMax(value);
	}
	else if (spinBox == spinBoxYMin)
	{
		yAxis->setMin(value);
	}
	else if (spinBox == spinBoxZoomFactor)
	{
		mZoomFactor = value;
	}
}


void ChartViewEx::ClearAll()
{
	mChart->removeAllSeries();
	mXMin = mXMax = mYMin = mYMax = 0;
}

void ChartViewEx::checkPointValid(QPointF& pos)
{
	QPointF origin = mChart->plotArea().bottomLeft();
	QPointF rightTopP = mChart->plotArea().topRight();

	if (pos.x() < origin.x())
	{
		pos.setX(origin.x());
	}

	if (pos.x() > rightTopP.x())
	{
		pos.setX(rightTopP.x());
	}

	if (pos.y() > origin.y())
	{
		pos.setY(origin.y());
	}

	if (pos.y() < rightTopP.y())
	{
		pos.setY(rightTopP.y());
	}
}

void ChartViewEx::saveImage()
{
	if (mChart->series().count() == 0)
		return;

	QPixmap map = this->grab(this->rect());

	QString newPath = QFileDialog::getSaveFileName(this, tr("Save Chart"),
		"/chart", tr("JPG files (*.JPG)"));

	if (newPath.isEmpty())
		return;

	map.save(newPath, "JPG");
}

void ChartViewEx::SelectAllNorNot()
{
	QAction* action = qobject_cast<QAction*>(sender());

	bool isDisplay = false;
	if (action == selectAllCurve)
	{
		isDisplay = true;
	}

	if (action == hideAllCurve)
	{
		isDisplay = false;
	}

	QList<QLegendMarker*> lstMarker = mChart->legend()->markers();
	for (int i = 0; i < lstMarker.count(); i++)
	{
		QLegendMarker* marker = lstMarker.at(i);
		switch (marker->type()) {
		case QLegendMarker::LegendMarkerTypeXY:
		{
			marker->setVisible(isDisplay);
			marker->series()->setVisible(isDisplay);

			qreal aplha = 1.0;
			if (!marker->series()->isVisible() && isLegendVisible)
			{
				aplha = 0.5;
				marker->setVisible(true);
			}

			QBrush brush;
			brush = marker->brush();
			QColor color;
			color = brush.color();
			color.setAlphaF(aplha);
			brush.setColor(color);
			marker->setBrush(brush);

			QPen pen;
			pen = marker->pen();
			color = pen.color();
			color.setAlphaF(aplha);
			pen.setColor(color);
			marker->setPen(pen);
			break;
		}
		case QLegendMarker::LegendMarkerTypeArea:
		case QLegendMarker::LegendMarkerTypeBar:
		case QLegendMarker::LegendMarkerTypePie:
		case QLegendMarker::LegendMarkerTypeBoxPlot:
		case QLegendMarker::LegendMarkerTypeCandlestick:
		default:
		{
			break;
		}
		}
	}

}

void ChartViewEx::markerVisible()
{
	isMarkerVisible = !isMarkerVisible;
	QList<QAbstractSeries*> lstSeries = mChart->series();
	for (int i = 0; i < lstSeries.count(); i++)
	{
		QLineSeries* series = qobject_cast<QLineSeries*>(lstSeries.at(i));
		series->setPointsVisible(isMarkerVisible);
	}
}

void ChartViewEx::setAxisXDecimalNumber(QString format)
{
	xAxis->setLabelFormat(format);
}

void ChartViewEx::setAxisYDecimalNumber(QString format)
{
	yAxis->setLabelFormat(format);
}
void ChartViewEx::setAxisReverse(bool xReverse, bool yReverse)
{
	xAxis->setReverse(xReverse);
	yAxis->setReverse(yReverse);
}

void ChartViewEx::addCurveData(QString name, QList<float> lstX, QList<float> lstY, QColor lineColor, int lineWidth)
{
	if (lstX.count() != lstY.count())
	{
		QMessageBox::warning(this, "Warning", "There are some errors in the data!");
		return;
	}

	int index = checkSeriesIsExistOrNot(name);
	if (index != -1)
	{
		QMessageBox::warning(this, "Warning", "There is exist the name in the chart!");
		return;
	}

	QLineSeries *series = new QLineSeries;
	QList<QPointF> lstP;
	if (mChart->series().count() == 0)
	{
		mXMax = mXMin = lstX[0];
		mYMax = mYMin = lstY[0];
	}

	for (int i = 0; i < lstX.count(); i++)
	{
		lstP.append(QPointF(lstX[i], lstY[i]));

		mXMax = lstX[i] > mXMax ? lstX[i] : mXMax;
		mXMin = lstX[i] < mXMin ? lstX[i] : mXMin;
		mYMax = lstY[i] > mYMax ? lstY[i] : mYMax;
		mYMin = lstY[i] < mYMin ? lstY[i] : mYMin;
	}

	series->append(lstP);

	connect(series, &QLineSeries::hovered, this, &ChartViewEx::setHoveredSigal);
	connect(series, &QLineSeries::doubleClicked, this, &ChartViewEx::showSetPropertyDialog);

	mChart->addSeries(series);

	series->setName(name);
	series->setColor(lineColor);
	series->pen().setWidth(lineWidth);

	xAxis->setRange(mXMin, mXMax);

	if (mYMax == mYMin)
	{
		mChart->axisY()->setRange(mYMin - 0.05, mYMax + 0.05);
	}
	else
	{
		mChart->axisY()->setRange(mYMin - (mYMax - mYMin) *0.05, mYMax + (mYMax - mYMin) * 0.05);
	}

	//mChart->setAxisX(xAxis, series);
	//mChart->setAxisY(yAxis, series);
	series->attachAxis(xAxis);
	series->attachAxis(yAxis);

	connectMarkers();
}

void ChartViewEx::appendCurveData(QString name, QList<float> lstX, QList<float> lstY)
{
	int index = checkSeriesIsExistOrNot(name);
	if (index == -1)
	{
		QMessageBox::warning(this, "Warning", QString("There is not the name(%1) in the chart!").arg(name));
		return;
	}

	appendCurveData(index, lstX, lstY);
}

void ChartViewEx::appendCurveData(int lineIndex, QList<float> lstX, QList<float> lstY)
{
	if (lineIndex < 0 || lineIndex > mChart->series().count())
	{
		QMessageBox::warning(this, "Warning", "The index out of range in the appendCurveData()");
		return;
	}

	QList<QPointF> lstP;
	for (int i = 0; i < lstX.count(); i++)
	{
		lstP.append(QPointF(lstX[i], lstY[i]));

		mXMax = lstX[i] > mXMax ? lstX[i] : mXMax;
		mXMin = lstX[i] < mXMin ? lstX[i] : mXMin;
		mYMax = lstY[i] > mYMax ? lstY[i] : mYMax;
		mYMin = lstY[i] < mYMin ? lstY[i] : mYMin;
	}

	QLineSeries *series = qobject_cast<QLineSeries*>(mChart->series().at(lineIndex));
	series->append(lstP);

	xAxis->setRange(mXMin, mXMax);

	if (mYMax == mYMin)
	{
		mChart->axisY()->setRange(mYMin - 0.05, mYMax + 0.05);
	}
	else
	{
		mChart->axisY()->setRange(mYMin - (mYMax - mYMin) *0.05, mYMax + (mYMax - mYMin) * 0.05);
	}
}

void ChartViewEx::deleteCurveData(int lineIndex)
{
	if (lineIndex < 0 || lineIndex > mChart->series().count())
	{
		QMessageBox::warning(this, "Warning", "The index out of range in the appendCurveData()");
		return;
	}

	mChart->series().removeAt(lineIndex);
}

void ChartViewEx::deleteCurveData(QString name)
{
	int index = checkSeriesIsExistOrNot(name);
	if (index == -1)
	{
		QMessageBox::warning(this, "Warning", QString("There is not the name(%1) in the chart!").arg(name));
		return;
	}

	deleteCurveData(index);
}

void ChartViewEx::hideCurveData(int lineIndex)
{
	if (lineIndex < 0 || lineIndex > mChart->series().count())
	{
		QMessageBox::warning(this, "Warning", "The index out of range in the hideCurveData()");
		return;
	}

	QLegendMarker* marker = mChart->legend()->markers().at(lineIndex);
	switch (marker->type()) {
	case QLegendMarker::LegendMarkerTypeXY:
	{
		marker->setVisible(false);
		marker->series()->setVisible(false);

		qreal aplha = 1.0;
		if (!marker->series()->isVisible() && isLegendVisible)
		{
			aplha = 0.5;
			marker->setVisible(true);
		}

		QBrush brush;
		brush = marker->brush();
		QColor color;
		color = brush.color();
		color.setAlphaF(aplha);
		brush.setColor(color);
		marker->setBrush(brush);

		QPen pen;
		pen = marker->pen();
		color = pen.color();
		color.setAlphaF(aplha);
		pen.setColor(color);
		marker->setPen(pen);
		break;
	}
	case QLegendMarker::LegendMarkerTypeArea:
	case QLegendMarker::LegendMarkerTypeBar:
	case QLegendMarker::LegendMarkerTypePie:
	case QLegendMarker::LegendMarkerTypeBoxPlot:
	case QLegendMarker::LegendMarkerTypeCandlestick:
	default:
	{
		break;
	}
	}

}

void ChartViewEx::hideCurveData(QString name)
{
	int index = checkSeriesIsExistOrNot(name);
	if (index == -1)
	{
		QMessageBox::warning(this, "Warning", QString("There is not the name(%1) in the chart!").arg(name));
		return;
	}

	hideCurveData(index);
}

int  ChartViewEx::checkSeriesIsExistOrNot(QString name)
{
	int index = -1;
	for (int i = 0; i < mChart->series().count(); i++)
	{
		if (name == mChart->series().at(i)->name())
		{
			index = i;
			break;
		}
	}

	return index;
}

void ChartViewEx::setChartBackgroundColor(QColor color)
{
	mChart->setBackgroundVisible(true);
	mChart->setBackgroundBrush(QBrush(color));
}

void ChartViewEx::setChartPlotAreaColor(QColor color)
{
	mChart->setPlotAreaBackgroundVisible(true);
	mChart->setPlotAreaBackgroundBrush(QBrush(color));
}

void ChartViewEx::setChartForegroundColor(QColor color)
{
	mChart->setTitleBrush(QBrush(color));
	xAxis->setTitleBrush(QBrush(color));
	yAxis->setTitleBrush(QBrush(color));
	//mChart->legend()->setColor(color);
}

void ChartViewEx::setGridColor(QColor color)
{
	xAxis->setGridLineColor(color);
	yAxis->setGridLineColor(color);
}

void ChartViewEx::setGridNumber(int xCount, int yCount)
{
	xAxis->setTickCount(xCount);
	yAxis->setTickCount(yCount);
}

void ChartViewEx::setXAxisRange(float minX, float maxX)
{
	xAxis->setRange(minX, maxX);
}

void ChartViewEx::setYAxisRange(float minY, float maxY)
{
	yAxis->setRange(minY, maxY);
}